package com.itcast.netty.client;

import com.itcast.netty.constants.ClientConstants;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;

/**
 * Netty 客户端
 *
 * @author eternity
 */
@Slf4j
public class NettyClient {
    /**
     * 初始化Bootstrap实例， 此实例是netty客户端应用开发的入口
     */
    private Bootstrap bootstrap;
    /**
     * 工人线程组
     */
    private EventLoopGroup worker;
    /**
     * 远程端口
     */
    private int port;
    /**
     * 远程服务器url
     */
    private String url;

    /**
     * 通过URL建立一个连接通道
     *
     * @param url  URL地址
     * @param port 端口
     */
    public NettyClient(String url, int port) {
        this.url = url;
        this.port = port;
        this.bootstrap = new Bootstrap();
        this.worker = new NioEventLoopGroup();
        bootstrap.group(worker);
        bootstrap.channel(NioSocketChannel.class);
    }

    /**
     * 关闭客户端
     */
    public void close() {
        log.info("关闭资源");
        worker.shutdownGracefully();
    }

    /**
     * 远程调用
     */
    public void start() {
        log.info("{} -> 启动连接 {} ：{}", this.getClass(), url, port);
        bootstrap.handler(new NettyClientHandler());
        ChannelFuture channelFuture = bootstrap.connect(url, port);
        int retry = 0;
        try {
            // 等待服务器监听端口关闭
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            // 重试
            retry ++;
            if (retry > ClientConstants.MAX_RETRY_TIMES) {
                throw new RuntimeException("调用出错");
            }
            // 避免死锁，建议线程睡眠100毫秒
            try {
                Thread.sleep(100);
            } catch (InterruptedException ex) {
                log.error("线程中断异常：{}", e.getMessage());
            }
            // 递归重复调用
            log.info("第{}次尝试...失败", retry);
            start();
        }
    }
}
